﻿using MusicExplorer.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using MusicExplorer.WebRepository.Interface;
using MusicExplorer.WebRepository.Service;
using System.Reflection;
using System.Threading;

namespace MusicExplorer.WebRepository
{
    public class BeatportWebRepository : WebRepositoryBase,
        IGroupTrackListingWebRepository, IGroupTopTrackListingWebRepository, IGroupFilterWebRepository,
        IArtistSearchWebRepository, IArtistFilterWebRepository, IArtistTopTrackListingWebRepository, IArtistTrackListingWebRepository
    {
        private const string m_url_GENRES = "http://api.beatport.com/catalog/3/genres";
        private const string m_url_TOPTRACKSFROMGROUP = "http://api.beatport.com/catalog/3/most-popular/genre?id={0}&page={1}&perPage={2}";
        private const string m_url_TRACKSFROMGROUP = "http://api.beatport.com/catalog/3/tracks?genreId={0}&page={1}&perPage={2}&sortBy=publishDate desc";
        private const string m_url_SEARCHARTISTS = "http://api.beatport.com/catalog/3/search?facets[]=fieldType:performer&query={0}&page={1}&perPage={2}";
        private const string m_url_TRACKSFROMARTIST = "http://api.beatport.com/catalog/3/tracks?performerId={0}&page={1}&perPage={2}&sortBy=publishDate desc";
        private const string m_url_TOPTRACKSFROMARTIST = "http://api.beatport.com/catalog/3/most-popular/artist?id={0}&page={1}&perPage={2}";

        public BeatportWebRepository()
        {
            m_web_repository = ServiceWebRepository.GetWebRepository(ServiceWebRepository.GetTypeWebRepository(TypeWebRepository.MusicStore), this.GetType().Name);
            m_result_per_page = 10;
        }

        #region TRACKS

        private List<TRACK> GetTracks(JObject json_object, CancellationToken token)
        {
            var tracks = new List<TRACK>();
            foreach (var json_track in (JArray)json_object["results"])
            {
                var track = new TRACK()
                {
                    track_name = (string)json_track["title"],
                    track_key = (string)json_track["id"],
                    group_key = (string)((JArray)json_track["genres"])[0]["id"],
                    web_repo_id = m_web_repository.web_repo_id,
                    track_mp3_url = (string)json_track["sampleUrl"],
                    track_img_url = (string)json_track["images"]["large"]["url"],
                    track_publish_date = DateTime.ParseExact((string)json_track["publishDate"], "yyyy-MM-dd", null)
                };

                track = ServiceWebRepository.InsertOrUpdateTrack(track);

                foreach (var json_artist in (JArray)json_track["artists"])
                {
                    var artist = new ARTIST()
                    {
                        artist_key = (string)json_artist["id"],
                        artist_name = (string)json_artist["name"],
                        web_repo_id = m_web_repository.web_repo_id
                    };

                    artist = ServiceWebRepository.InsertOrUpdateArtist(artist);

                    var jn_artist_track = new JN_ARTIST_TRACK()
                    {
                        artist_key = artist.artist_key,
                        track_key = track.track_key,
                        web_repo_id = m_web_repository.web_repo_id,
                        type_artist_id = ServiceWebRepository.GetRefTypeArtist(GetTypeArtist((string)json_artist["type"])).type_artist_id
                    };

                    jn_artist_track = ServiceWebRepository.InsertJnArtistTrack(jn_artist_track);

                    jn_artist_track.REF_TYPE_ARTIST = ServiceWebRepository.GetRefTypeArtist(GetTypeArtist((string)json_artist["type"]));
                    jn_artist_track.ARTIST = artist;
                    track.JN_ARTIST_TRACK.Add(jn_artist_track);
                }

                tracks.Add(track);

                token.ThrowIfCancellationRequested();
            }
            return tracks;
        }

        public async Task<List<TRACK>> GetTracksFromGroupAsync(WebClient webClient, CancellationToken token, GROUP group, int page)
        {
            //CuttingTimer(token, 1);
            token.ThrowIfCancellationRequested();
            //JObject json_object = JObject.Parse(await ServiceWebRepository.GetLocalDataAsync(@"../../../MusicExplorer.WebRepository/DataFile/BeatportTracks.txt"));
            JObject json_object = JObject.Parse(await ServiceWebRepository.GetUrlDataAsync(webClient, string.Format(m_url_TRACKSFROMGROUP, group.group_key, page, m_result_per_page)));
            token.ThrowIfCancellationRequested();
            var tracks = GetTracks(json_object, token);
            return tracks;
        }

        public async Task<List<TRACK>> GetTopTracksFromGroupAsync(WebClient webClient, CancellationToken token, GROUP group, int page)
        {
            token.ThrowIfCancellationRequested();
            JObject json_object = JObject.Parse(await ServiceWebRepository.GetUrlDataAsync(webClient, string.Format(m_url_TOPTRACKSFROMGROUP, group.group_key, page, m_result_per_page)));
            token.ThrowIfCancellationRequested();
            var tracks = GetTracks(json_object, token);
            return tracks;
        }

        public async Task<List<TRACK>> GetTracksFromArtistAsync(WebClient webClient, CancellationToken token, ARTIST artist, int page)
        {
            token.ThrowIfCancellationRequested();
            JObject json_object = JObject.Parse(await ServiceWebRepository.GetUrlDataAsync(webClient, string.Format(m_url_TRACKSFROMARTIST, artist.artist_key, page, m_result_per_page)));
            token.ThrowIfCancellationRequested();
            var tracks = GetTracks(json_object, token);
            return tracks;
        }

        public async Task<List<TRACK>> GetTopTracksFromArtistAsync(WebClient webClient, CancellationToken token, ARTIST artist, int page)
        {
            token.ThrowIfCancellationRequested();
            JObject json_object = JObject.Parse(await ServiceWebRepository.GetUrlDataAsync(webClient, string.Format(m_url_TOPTRACKSFROMARTIST, artist.artist_key, page, m_result_per_page)));
            token.ThrowIfCancellationRequested();
            var tracks = GetTracks(json_object, token);
            return tracks;
        }

        #endregion

        #region GROUPS

        public async Task<List<GROUP>> GetGroupsAsync(WebClient webClient, CancellationToken token)
        {
            var groups = new List<GROUP>();

            token.ThrowIfCancellationRequested();
            JObject json_object = JObject.Parse(await ServiceWebRepository.GetUrlDataAsync(webClient, m_url_GENRES));
            token.ThrowIfCancellationRequested();
            foreach (var json_genre in (JArray)json_object["results"])
            {
                var group = new GROUP()
                {
                    group_key = (string)json_genre["id"],
                    group_name = (string)json_genre["name"],
                    web_repo_id = m_web_repository.web_repo_id
                };

                group = ServiceWebRepository.InsertOrUpdateGroup(group);

                groups.Add(group);

                token.ThrowIfCancellationRequested();
            }

            return groups;
        }

        #endregion

        #region ARTISTS

        public async Task<List<ARTIST>> SearchArtist(WebClient webClient, CancellationToken token, string searchTerms, int page)
        {
            var artists = new List<ARTIST>();

            token.ThrowIfCancellationRequested();
            JObject json_object = JObject.Parse(await ServiceWebRepository.GetUrlDataAsync(webClient, string.Format(m_url_SEARCHARTISTS, searchTerms, page, m_result_per_page)));
            token.ThrowIfCancellationRequested();
            foreach (var json_artist in (JArray)json_object["results"])
            {
                var artist = new ARTIST()
                {
                    artist_key = (string)json_artist["id"],
                    artist_name = (string)json_artist["name"],
                    web_repo_id = m_web_repository.web_repo_id
                };

                artists.Add(artist);

                token.ThrowIfCancellationRequested();
            }

            return artists;
        }

        private TypeArtist GetTypeArtist(string type)
        {
            switch (type)
            {
                case "artist":
                    return TypeArtist.Original;
                case "remixer":
                    return TypeArtist.Remixer;
                default:
                    return TypeArtist.Original;
            }
        }

        #endregion
    }
}
